package io.github.wppli.domain.authenticate.service;

import cc.jq1024.middleware.redisson.IRedissonService;
import cc.jq1024.middleware.token.service.ITokenService;
import io.github.wppli.domain.authenticate.model.entity.UserEntity;
import io.github.wppli.domain.authenticate.repository.IAuthenticateRepository;
import io.github.wppli.domain.authenticate.model.entity.SingInEntity;
import io.github.wppli.domain.authenticate.model.entity.SingInUserInfoEntity;
import io.github.wppli.domain.authenticate.service.engine.IEngine;
import io.github.wppli.domain.authenticate.service.engine.IMessageLoader;
import io.github.wppli.domain.authenticate.service.engine.factory.AuthenticateFactory;
import io.github.wppli.sms.domain.RandomCodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static io.github.wppli.types.common.Constant.LOGIN_CODE;
import static io.github.wppli.types.common.Constant.LOGIN_CODE_EXP;

/**
 * @author li--jiaqiang 2024−12−23
 */
@Service
public class AuthenticateService implements IAuthenticateService {

    private static final Logger log = LoggerFactory.getLogger(AuthenticateService.class);

    private final AuthenticateFactory authenticateFactory;
    private final ITokenService tokenService;
    private final IRedissonService redissonService;
    private final IAuthenticateRepository userRepository;

    public AuthenticateService(AuthenticateFactory authenticateFactory, ITokenService tokenService, IRedissonService redissonService, PasswordEncoder passwordEncoder, IAuthenticateRepository userRepository) {
        this.authenticateFactory = authenticateFactory;
        this.tokenService = tokenService;
        this.redissonService = redissonService;
        this.userRepository = userRepository;
    }

    /**
     * 快捷登录
     * @param singInEntity 登录实体
     */
    @Override
    public SingInUserInfoEntity signIn(SingInEntity singInEntity) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        // 1. 根据code拿到不同的执行器
        Map<String, IEngine> engineMap = authenticateFactory.getEngineMap();
        IEngine engine = engineMap.get(singInEntity.getCode().getActuatorName());

        // 0. 获取要执行的方法名
        String method = AuthenticateFactory.getDigitalIdentityType(singInEntity.getContactInformation(), AuthenticateFactory.DigitalIdentityType.queryUserInfo);
        // 1. 获取 userRepository 的 Class 对象
        Class<?> repositoryClass = userRepository.getClass();
        // 2. 获取 queryUserInfoWithEmail 方法
        Method queryMethod = repositoryClass.getMethod(method, String.class);
        // 3. 获取 singInEntity.getContactInformation() 的返回值
        String contactInformation = singInEntity.getContactInformation();
        // 4. 调用 queryUserInfoWithEmail 方法
        UserEntity userEntity = (UserEntity) queryMethod.invoke(userRepository, contactInformation);

        // 2. 执行不同得逻辑（密码登录和验证码登录）
        engine.loginEngine(singInEntity, userEntity);

        // 3. 验证成功，生成token进行返回
        String jwt = tokenService.createJWT(new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;
            {
                put("contactInformation", singInEntity.getContactInformation());
                put("userId", userEntity.getId());
            }
        }, userEntity.getId().toString());

        return SingInUserInfoEntity.builder()
                .token(jwt)
                .userEntity(userEntity)
                .build();
    }

    @Override
    public String genCode(String contactInformation, String prefix) {
        String key = prefix + contactInformation;
        String value = redissonService.getValue(key);
        if (!StringUtils.isAnyBlank(value)) {
            redissonService.setValue(key, value, LOGIN_CODE_EXP, TimeUnit.MINUTES);
            return value;
        }
        value = RandomCodeUtil.generateRandomCode(4);
        redissonService.setValue(key, value, LOGIN_CODE_EXP, TimeUnit.MINUTES);
        log.info("生成验证码: {}", value);
        return value;
    }

    @Override
    public void sendCode(String contactInformation, int type, String code) {
        Map<String, IMessageLoader> messageLoaderMap = authenticateFactory.getMessageLoaderMap();
        AuthenticateFactory.MessageLoaderType messageLoaderType = AuthenticateFactory.getMessageLoaderType(type);
        IMessageLoader iMessageLoader = messageLoaderMap.get(messageLoaderType.getActuatorName());
        iMessageLoader.sendCode(code, contactInformation);
        log.info("验证码：{} 已发送：{}", code, contactInformation);
    }

    @Override
    public boolean verifyCode(String contactInformation, String code) {
        String key = LOGIN_CODE + contactInformation;
        String value = redissonService.getValue(key);
        return !StringUtils.isAnyBlank(value) && code.equals(value);
    }

}